package com.haoge7777.weblog.common.aspect;


import com.haoge7777.weblog.common.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

@Aspect
@Component
@Slf4j
public class ApiOperationLogAspect {

    /**
     * 创建以自定义@ApiOperationLog注解为切点，凡是添加自定义注解的方法，都会执行环绕中的代码
     */
    @Pointcut("@annotation(com.haoge7777.weblog.common.aspect.ApiOperationLog)")
    public void apiOperationLog(){}


    /**
     * 环绕
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws  Throwable {

    try {
        //请求开始时间
        long startTime = System.currentTimeMillis();

        //MDC  trace表示跟踪ID，指的是这里直接使用的UUID
        MDC.put("traceId", UUID.randomUUID().toString());

        //获取被请求的类和方法
        String className = joinPoint.getTarget().getClass().getSimpleName(); //获取类对象中的类名中的类简化名称
        String methodName = joinPoint.getSignature().getName(); //获取方法中的签名中的方法的名称

        //请求入参
        Object[] args = joinPoint.getArgs();

        //入参转JSON字符
        String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining("，"));

        //功能描述信息
        String description = getApiOperationLogDescription(joinPoint);

        //打印请求相关参数
        log.info("=========== 请求开始：[{}]，入参：{}，请求类：{}，请求方法：{} ======================",description,argsJsonStr,className,methodName);

        //执行切点方法
        Object result = joinPoint.proceed();

        //执行耗时
        long executionTime = System.currentTimeMillis() - startTime;

        //打印出参等相关信息
        log.info("========== 请求结束：[{}]，耗时；{}ms，出参：{} =======================",description,executionTime, JsonUtil.toJsonString(result));

        return result;
    } finally {
        MDC.clear();
    }
    }
    /**
     * 获取注释的描述消息
     *
     */

    private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint){

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        Method method = signature.getMethod();

        ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);

        return apiOperationLog.description();

    }

    /**
     * 转JSON字符串
     *
     */

    private Function<Object,String> toJsonStr(){
        return arg -> JsonUtil.toJsonString(arg);
    }

}




